package cn.lg.soar.general.s3;

import cn.lg.soar.common.util.FileTypeUtils;
import cn.lg.soar.common.util.FileUtil;
import cn.lg.soar.common.util.StreamUtil;
import cn.lg.soar.general.api.enums.FileStorageTypeEnum;
import cn.lg.soar.general.api.enums.ThumbnailSizeEnum;
import cn.lg.soar.general.entity.FileStorage;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.Bucket;
import com.amazonaws.services.s3.model.S3Object;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/3/1 17:25
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public interface FileTemplate {

    Logger LOGGER = LoggerFactory.getLogger(FileTemplate.class);

    /**
     * 创建bucket
     * @param bucketName bucket名称
     */
    void createBucket(String bucketName);

    /**
     * 通过bucket名称删除bucket
     * @param bucketName bucket名称
     */
    void removeBucket(String bucketName);

    /**
     * 获取所有的bucket
     * @return
     */
    List<Bucket> listBuckets();

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @param stream 文件流
     * @throws Exception
     */
    void upload(String bucketName, String filename, InputStream stream);

    /**
     * 上传文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @param file 文件
     */
    default void upload(String bucketName, String filename, File file) {
        try {
            upload(bucketName, filename, Files.newInputStream(file.toPath()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取文件流
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @return
     */
    InputStream getInputStream(String bucketName, String filename);

    /**
     * 获取文件流
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @param size
     * @return
     */
    default InputStream getInputStream(String bucketName, String filename, ThumbnailSizeEnum size) {
        if (size == null || !FileTypeUtils.isImage(filename)) {
            return getInputStream(bucketName, filename);
        }
        int i = filename.lastIndexOf(".");
        String tfn = filename.substring(0, i + 1) + size + filename.substring(i);
        try {
            return getInputStream(bucketName, tfn);
        } catch (AmazonS3Exception ignored) {

        }
        S3Object object = getObject(bucketName, filename, size);
        return object.getObjectContent();
    }

    /**
     * 获取文件
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @return S3Object
     */
    S3Object getObject(String bucketName, String filename);

    default S3Object getObject(String bucketName, String filename, ThumbnailSizeEnum size) {
        // 返回源文件
        if (size == null || !FileTypeUtils.isImage(filename)) {
            return getObject(bucketName, filename);
        }

        // 尝试读取缩略图
        int i = filename.lastIndexOf(".");
        String tfn = filename.substring(0, i + 1) + size + filename.substring(i);
        try {
            return getObject(bucketName, tfn);
        } catch (AmazonS3Exception ignored) {

        }
        // 尝试生成缩略图
        S3Object s3Object = getObject(bucketName, filename);
        File tempFile = null;
        OutputStream outputStream = null;
        InputStream inputStream = null;
        try {
            // 读取图片
            BufferedImage image = ImageIO.read(s3Object.getObjectContent());
            int w = size.getWidth();
            int h = size.getHeight();
            if (image.getWidth() > w || image.getHeight() > w) {
                // 压缩处理
                tempFile = File.createTempFile("lg-soar-file", UUID.randomUUID().toString());
                Path path = tempFile.toPath();
                outputStream = Files.newOutputStream(path);
                inputStream = Files.newInputStream(path);
                Thumbnails.of(image).size(w, h)
                        .outputQuality(0.7)
                        .outputFormat(FileUtil.getSuffix(filename))
                        .toOutputStream(outputStream);
                // 保存压缩文件
                upload(bucketName, tfn, inputStream);
                inputStream.close();
                // 返回压缩图
                inputStream = Files.newInputStream(path);
                s3Object.getObjectMetadata().setContentLength(tempFile.length());
                s3Object.setObjectContent(inputStream);
            } else {
                // 复制原图
                asyncUpload(bucketName, tfn, s3Object.getObjectContent());
                s3Object.getObjectContent().reset();
            }
            return s3Object;
        } catch (IOException | RuntimeException e2) {
            LOGGER.error("图片压缩异常", e2);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    LOGGER.error("关闭流失败", e);
                }
            }
            if (tempFile != null) {
                try {
                    tempFile.delete();
                } catch (Exception e) {
                    LOGGER.error("关闭临时文件", e);
                }
            }
        }
        // 兜底
        return getObject(bucketName, filename);
    }

    /**
     * 异步上传
     * @param bucketName
     * @param filename
     * @param stream
     * @return
     */
    default CompletableFuture<Void> asyncUpload(String bucketName, String filename, InputStream stream) {
        return CompletableFuture.runAsync(() -> {
            upload(bucketName, filename, stream);
        });
    }

    /**
     * 根据文件前置查询文件
     * @param bucketName bucket名称
     * @param prefix 前缀
     * @param recursive 是否递归查询
     * @return S3ObjectSummary 列表
     */
    List<S3ObjectSummary> listObjects(String bucketName, String prefix, boolean recursive);

    /**
     * 获取对象的访问路径
     * @param bucketName
     * @param filename
     * @param expires
     * @return
     */
    String getUrl(String bucketName, String filename, Integer expires);

    /**
     * 获取对象的访问路径
     * @param bucketName
     * @param filename
     * @param expires
     * @return
     */
    String getUrl(String bucketName, String filename);

    /**
     * 通过bucketName和filename删除对象
     * @param bucketName
     * @param filename
     * @throws Exception
     */
    void removeFile(String bucketName, String filename);

    /**
     * 判断文件是否存在
     * @param bucketName bucket名称
     * @param filename 文件名称
     * @return
     */
    boolean isExist(String bucketName, String filename);

    /**
     * 获取配置版本
     * @return
     */
    int getConfigVersion();

    /**
     * 测试是否可用
     * @return
     */
    void test();

    /**
     * 关闭连接
     */
    void disconnect();

    /**
     * 创建实例
     * @param fileStorage
     * @return
     */
    static FileTemplate create(FileStorage fileStorage) {
        FileStorageTypeEnum type = fileStorage.getType();
        if (FileStorageTypeEnum.AMAZON_S3.equals(type)) {
            return new AmazonS3FileTemplateImpl(fileStorage);
        }
        if (FileStorageTypeEnum.FTP.equals(type)) {
            return new FtpFileTemplateImpl(fileStorage);
        }
        return new LocalFileTemplateImpl(fileStorage);
    }

}